package com.yc.cloud.admin.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yc.cloud.admin.dto.RecordingConfig;
import com.yc.cloud.admin.service.SysDictService;
import com.yc.cloud.admin.service.StorageStrategyResolver;
import com.yc.cloud.api.constants.SystemConfigConstants;
import com.yc.cloud.entity.HwCameraStorageRelation;
import com.yc.cloud.entity.HwCameraStorageStrategy;
import com.yc.cloud.entity.HwCameraStorageStrategyTimeslotRelation;
import com.yc.cloud.entity.HwCameraTimeSlot;
import com.yc.cloud.mapper.HwCameraStorageRelationMapper;
import com.yc.cloud.mapper.HwCameraStorageStrategyMapper;
import com.yc.cloud.mapper.HwCameraStorageStrategyTimeslotRelationMapper;
import com.yc.cloud.mapper.HwCameraTimeSlotMapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import cn.hutool.core.util.StrUtil;

import java.time.LocalDate;
import java.time.LocalTime;
import java.util.Arrays;
import java.util.List;

/**
 * 存储策略解析服务实现类
 *
 * @author kinggu
 * @since 2025-09-16
 */
@Service
@Slf4j
public class StorageStrategyResolverImpl implements StorageStrategyResolver {

    @Resource
    private HwCameraStorageStrategyMapper strategyMapper;

    @Resource
    private HwCameraStorageRelationMapper relationMapper;

    @Resource
    private HwCameraTimeSlotMapper timeSlotMapper;

    @Resource
    private HwCameraStorageStrategyTimeslotRelationMapper strategyTimeslotRelationMapper;

    @Resource
    private SysDictService sysDictService;

    @Override
    public HwCameraStorageStrategy getEffectiveStrategy(Long cameraId) {
        log.debug("获取摄像头 {} 的有效存储策略", cameraId);

        // 复用getCurrentRecordingConfig的逻辑，只返回策略部分
        RecordingConfig config = getCurrentRecordingConfig(cameraId);
        return config.getStrategy();
    }

    @Override
    public RecordingConfig getCurrentRecordingConfig(Long cameraId) {
        log.debug("获取摄像头 {} 当前时间的录制配置", cameraId);

        LocalTime now = LocalTime.now();
        int dayOfWeek = LocalDate.now().getDayOfWeek().getValue(); // 1=Monday, 7=Sunday

        // 1. 查找摄像头的所有个人策略
        List<HwCameraStorageRelation> relations = relationMapper.selectList(
                new QueryWrapper<HwCameraStorageRelation>()
                        .eq(HwCameraStorageRelation.CameraId, cameraId));

        HwCameraStorageStrategy strategy = null;
        HwCameraTimeSlot activeSlot = null;
        String configSource = SystemConfigConstants.CONFIG_SOURCE_NONE;

        // 1. 如果摄像头没有绑定的策略，使用全局默认策略
        if (relations.isEmpty()) {
            strategy = getGlobalDefaultStrategy();
            if (strategy != null) {
                log.debug("使用全局默认策略: {}", strategy.getStrategyName());
                configSource = SystemConfigConstants.CONFIG_SOURCE_GLOBAL;
                // 查找全局策略的活跃时间段
                activeSlot = findActiveTimeSlotForStrategy(strategy.getId(), now, dayOfWeek);
            } else {
                log.warn("未找到有效的存储策略");
                return RecordingConfig.builder()
                        .shouldRecord(false)
                        .configSource(SystemConfigConstants.CONFIG_SOURCE_NONE)
                        .build();
            }

        } else {
            // 2. 遍历所有绑定的策略，查找第一个有活跃时间段的策略
            log.debug("摄像头 {} 绑定了 {} 个策略", cameraId, relations.size());

            for (HwCameraStorageRelation relation : relations) {
                HwCameraStorageStrategy candidateStrategy = strategyMapper.selectById(relation.getStrategyId());
                if (candidateStrategy != null
                        && candidateStrategy.getStatus().equals(SystemConfigConstants.STRATEGY_STATUS_ENABLED)
                        && candidateStrategy.getIsDeleted().equals(SystemConfigConstants.NOT_DELETED)) {
                    // 检查该策略是否有活跃时间段
                    HwCameraTimeSlot candidateSlot = findActiveTimeSlotForStrategy(candidateStrategy.getId(),
                            now,
                            dayOfWeek);
                    if (candidateSlot != null) {
                        // 找到第一个有活跃时间段的策略
                        strategy = candidateStrategy;
                        activeSlot = candidateSlot;
                        configSource = SystemConfigConstants.CONFIG_SOURCE_CAMERA;
                        log.debug("使用摄像头个人策略: {} (时间段: {})", strategy.getStrategyName(), activeSlot.getSlotName());
                        break;
                    }
                }
            }
        }

        return RecordingConfig.builder()
                .strategy(strategy)
                .timeSlot(activeSlot)
                .shouldRecord(activeSlot != null)
                .configSource(configSource)
                .build();
    }

    /**
     * 查找策略的活跃时间段（私有辅助方法）
     */
    private HwCameraTimeSlot findActiveTimeSlotForStrategy(Long strategyId, LocalTime now, int dayOfWeek) {
        log.debug("查找策略 {} 当前时间的活跃时间段", strategyId);

        // 1. 查询策略关联的时间段ID列表
        List<HwCameraStorageStrategyTimeslotRelation> relations = strategyTimeslotRelationMapper.selectList(
                new QueryWrapper<HwCameraStorageStrategyTimeslotRelation>()
                        .eq(HwCameraStorageStrategyTimeslotRelation.StrategyId, strategyId)
                        .eq(HwCameraStorageStrategyTimeslotRelation.Status,
                                SystemConfigConstants.STRATEGY_STATUS_ENABLED));

        if (relations.isEmpty()) {
            log.debug("策略 {} 没有关联的时间段", strategyId);
            return null;
        }

        // 2. 获取时间段ID列表
        List<Long> timeSlotIds = relations.stream()
                .map(HwCameraStorageStrategyTimeslotRelation::getTimeSlotId)
                .toList();

        // 3. 查询这些时间段的详细信息
        List<HwCameraTimeSlot> timeSlots = timeSlotMapper.selectList(
                new QueryWrapper<HwCameraTimeSlot>()
                        .in(HwCameraTimeSlot.ID, timeSlotIds)
                        .eq(HwCameraTimeSlot.Status, SystemConfigConstants.STRATEGY_STATUS_ENABLED)
                        .eq(HwCameraTimeSlot.IsDeleted, SystemConfigConstants.NOT_DELETED));

        // 4. 检查哪个时间段当前活跃
        for (HwCameraTimeSlot timeSlot : timeSlots) {
            if (isTimeSlotActive(timeSlot, now, dayOfWeek)) {
                log.debug("找到活跃时间段: {}", timeSlot.getSlotName());
                return timeSlot;
            }
        }

        log.debug("策略 {} 当前时间没有活跃的时间段", strategyId);
        return null;
    }

    @Override
    public HwCameraTimeSlot findActiveTimeSlot(Long strategyId) {
        LocalTime now = LocalTime.now();
        int dayOfWeek = LocalDate.now().getDayOfWeek().getValue();
        return findActiveTimeSlotForStrategy(strategyId, now, dayOfWeek);
    }

    @Override
    public HwCameraStorageStrategy getGlobalDefaultStrategy() {
        return strategyMapper.selectOne(
                new QueryWrapper<HwCameraStorageStrategy>()
                        .eq(HwCameraStorageStrategy.IsGlobalDefault, SystemConfigConstants.GLOBAL_STRATEGY_YES)
                        .eq(HwCameraStorageStrategy.Status, SystemConfigConstants.STRATEGY_STATUS_ENABLED)
                        .eq(HwCameraStorageStrategy.IsDeleted, SystemConfigConstants.NOT_DELETED)
                        .last("LIMIT 1"));
    }

    @Override
    public boolean isTimeSlotActive(HwCameraTimeSlot timeSlot, LocalTime checkTime, int dayOfWeek) {
        // 检查星期是否匹配
        if (StrUtil.isBlank(timeSlot.getDaysOfWeek())) {
            return false;
        }

        boolean dayMatches = Arrays.stream(timeSlot.getDaysOfWeek().split(","))
                .mapToInt(Integer::parseInt)
                .anyMatch(day -> day == dayOfWeek);

        if (!dayMatches) {
            return false;
        }

        // 检查时间是否匹配
        LocalTime startTime = timeSlot.getStartTime();
        LocalTime endTime = timeSlot.getEndTime();

        // 自动判断是否跨日
        if (timeSlot.isCrossDay()) {
            // 跨日时间段：如 20:00 - 06:00
            return checkTime.compareTo(startTime) >= 0 || checkTime.compareTo(endTime) <= 0;
        } else {
            // 普通时间段：如 08:00 - 18:00
            return checkTime.compareTo(startTime) >= 0 && checkTime.compareTo(endTime) <= 0;
        }
    }
}